/** 通知 */
export enum NotifyType {
  Login = 'login',
  Init = 'init',
  ChangChild = 'changChild',
  BackIndex = 'backIndex',
}

export enum NotifyOption {
  Empty = 'empty',
  List = 'list',
  Add = 'add',
  Update = 'update',
  Remove = 'remove',
} 

export class AppNotify {
  private static _instance: AppNotify;
  private listerners: Map<NotifyType, Observer[]>;
  constructor() {
    this.listerners = new Map<NotifyType, Observer[]>();
    console.log("lazy loading singleton has created");
  }

  public static get instance(): AppNotify {
    if (!this._instance) {
      this._instance = new AppNotify();
    } else {
      //   console.log('lazy loading singleton has created');
    }
    return this._instance;
  }
  public addListener(notify: NotifyType, callback: Function, ctx: any): void {
    const key = notify;
    if (!this.listerners.has(key)) {
      this.listerners.set(key, []);
    }
    const list = this.listerners.get(key);
    if (!list) {
      return;
    }
    for (const item of list) {
      if (item.compare(ctx)) {
        return;
      }
    }
    list.push(new Observer(callback, ctx));
  }

  public removeListener(notify: NotifyType, ctx: any): void {
    const key = notify;
    if (!this.listerners.has(key)) {
      return;
    }
    const list = this.listerners.get(key);
    if (!list) {
      return;
    }
    for (let i = 0; i < list.length; i++) {
      if (list[i].compare(ctx)) {
        list.splice(i, 1);
        break;
      }
    }
    if (list.length < 1) {
      this.listerners.delete(key);
    }
  }

  public send(notify: NotifyType, opt: NotifyOption, msg: string) {
    const key = notify;
    if (!this.listerners.has(key)) {
      return;
    }
    const list = this.listerners.get(key);
    if (!list) {
      return;
    }
    for (const item of list) {
      item.notify(opt, msg);
    }
  }
}

export class Observer {
  private callback: Function;
  private context: any = null;

  public constructor(fun: Function, ctx: string) {
    this.callback = fun;
    this.context = ctx;
  }

  public notify(opt: NotifyOption, msg: string): void {
    this.callback.call(this.context, opt, msg);
  }

  public compare(ctx: any): boolean {
    return this.context == ctx;
  }
}
